package com.isoft.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.isoft.entity.*;
import com.isoft.mapper.*;
import com.isoft.utils.XmlParseUtil;
import generator.mapper.CheckinDisplayMapper;
import generator.mapper.FlightBaseMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

/**
 * XML数据导入服务
 * 支持BASE和DFME所有类型的XML数据一次性导入
 */
@Service
public class XmlImportService {

    private static final Logger logger = LoggerFactory.getLogger(XmlImportService.class);

    @Autowired
    private MsgMetaMapper msgMetaMapper;

    @Autowired
    private AirportInfoMapper airportInfoMapper;

    @Autowired
    private FlightDynamicMapper flightDynamicMapper;

    @Autowired
    private GateAssignmentMapper gateAssignmentMapper;

    @Autowired
    private StandAssignmentMapper standAssignmentMapper;

    @Autowired
    private BeltAssignmentMapper beltAssignmentMapper;

    @Autowired
    private FlightBaseMapper flightBaseMapper;

    @Autowired
    private CheckinDisplayMapper checkinDisplayMapper;

    /**
     * 导入结果统计
     */
    public static class ImportResult {
        private int totalFiles;
        private int successFiles;
        private int failedFiles;
        private int msgMetaCount;
        private int airportInfoCount;
        private int flightDynamicCount;
        private int gateAssignmentCount;
        private int standAssignmentCount;
        private int beltAssignmentCount;
        private int flightBaseCount;
        private int checkinDisplayCount;
        private List<String> errorMessages;
        private Map<String, Integer> messageTypeCounts;

        public ImportResult() {
            this.errorMessages = new ArrayList<>();
            this.messageTypeCounts = new HashMap<>();
        }

        // Getters and Setters
        public int getTotalFiles() { return totalFiles; }
        public void setTotalFiles(int totalFiles) { this.totalFiles = totalFiles; }

        public int getSuccessFiles() { return successFiles; }
        public void setSuccessFiles(int successFiles) { this.successFiles = successFiles; }

        public int getFailedFiles() { return failedFiles; }
        public void setFailedFiles(int failedFiles) { this.failedFiles = failedFiles; }

        public int getMsgMetaCount() { return msgMetaCount; }
        public void setMsgMetaCount(int msgMetaCount) { this.msgMetaCount = msgMetaCount; }

        public int getAirportInfoCount() { return airportInfoCount; }
        public void setAirportInfoCount(int airportInfoCount) { this.airportInfoCount = airportInfoCount; }

        public int getFlightDynamicCount() { return flightDynamicCount; }
        public void setFlightDynamicCount(int flightDynamicCount) { this.flightDynamicCount = flightDynamicCount; }

        public int getGateAssignmentCount() { return gateAssignmentCount; }
        public void setGateAssignmentCount(int gateAssignmentCount) { this.gateAssignmentCount = gateAssignmentCount; }

        public int getStandAssignmentCount() { return standAssignmentCount; }
        public void setStandAssignmentCount(int standAssignmentCount) { this.standAssignmentCount = standAssignmentCount; }

        public int getBeltAssignmentCount() { return beltAssignmentCount; }
        public void setBeltAssignmentCount(int beltAssignmentCount) { this.beltAssignmentCount = beltAssignmentCount; }

        public int getFlightBaseCount() { return flightBaseCount; }
        public void setFlightBaseCount(int flightBaseCount) { this.flightBaseCount = flightBaseCount; }

        public int getCheckinDisplayCount() { return checkinDisplayCount; }
        public void setCheckinDisplayCount(int checkinDisplayCount) { this.checkinDisplayCount = checkinDisplayCount; }

        public List<String> getErrorMessages() { return errorMessages; }
        public void setErrorMessages(List<String> errorMessages) { this.errorMessages = errorMessages; }

        public Map<String, Integer> getMessageTypeCounts() { return messageTypeCounts; }
        public void setMessageTypeCounts(Map<String, Integer> messageTypeCounts) { this.messageTypeCounts = messageTypeCounts; }

        public void addErrorMessage(String message) {
            this.errorMessages.add(message);
        }

        public void incrementMessageTypeCount(String messageType) {
            this.messageTypeCounts.put(messageType,
                    this.messageTypeCounts.getOrDefault(messageType, 0) + 1);
        }
    }

    /**
     * 批量导入项目中的所有XML文件
     */
    @Transactional(rollbackFor = Exception.class)
    public ImportResult importAllXmlFiles() {
        String xmlFolderPath = "src/main/resources/xml";
        return importXmlFromFolder(xmlFolderPath);
    }

    /**
     * 从指定文件夹导入XML文件
     */
    @Transactional(rollbackFor = Exception.class)
    public ImportResult importXmlFromFolder(String xmlFolderPath) {
        logger.info("开始批量导入XML文件，文件夹路径: {}", xmlFolderPath);

        ImportResult result = new ImportResult();

        try {
            Map<String, XmlParseUtil.ParseResult> parseResults = XmlParseUtil.parseXmlFolder(xmlFolderPath);
            result.setTotalFiles(parseResults.size());

            if (parseResults.isEmpty()) {
                result.addErrorMessage("未找到任何XML文件或文件夹不存在: " + xmlFolderPath);
                return result;
            }

            // 处理每个解析结果
            for (Map.Entry<String, XmlParseUtil.ParseResult> entry : parseResults.entrySet()) {
                String fileName = entry.getKey();
                XmlParseUtil.ParseResult parseResult = entry.getValue();

                try {
                    processParseResult(parseResult, result);
                    result.setSuccessFiles(result.getSuccessFiles() + 1);
                    logger.debug("成功处理文件: {}", fileName);
                } catch (Exception e) {
                    result.setFailedFiles(result.getFailedFiles() + 1);
                    result.addErrorMessage("处理文件失败: " + fileName + ", 错误: " + e.getMessage());
                    logger.error("处理文件失败: {}", fileName, e);
                }
            }

            logger.info("批量导入完成 - 总文件数: {}, 成功: {}, 失败: {}",
                    result.getTotalFiles(), result.getSuccessFiles(), result.getFailedFiles());

        } catch (Exception e) {
            result.addErrorMessage("批量导入过程中发生错误: " + e.getMessage());
            logger.error("批量导入过程中发生错误", e);
        }

        return result;
    }

    /**
     * 按消息类型导入XML文件
     */
    @Transactional(rollbackFor = Exception.class)
    public ImportResult importXmlByMessageType(String messageType) {
        logger.info("开始按消息类型导入XML文件，消息类型: {}", messageType);

        ImportResult result = new ImportResult();
        String xmlFolderPath = "src/main/resources/xml";

        try {
            Map<String, XmlParseUtil.ParseResult> parseResults = XmlParseUtil.parseXmlFolder(xmlFolderPath);

            // 过滤指定消息类型的文件
            Map<String, XmlParseUtil.ParseResult> filteredResults = parseResults.entrySet().stream()
                    .filter(entry -> {
                        XmlParseUtil.ParseResult parseResult = entry.getValue();
                        if (parseResult.getMsgMeta() != null) {
                            String type = parseResult.getMsgMeta().getType() + "-" + parseResult.getMsgMeta().getStyp();
                            return messageType.equals(type);
                        }
                        return false;
                    })
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            result.setTotalFiles(filteredResults.size());

            if (filteredResults.isEmpty()) {
                result.addErrorMessage("未找到指定消息类型的XML文件: " + messageType);
                return result;
            }

            // 处理过滤后的结果
            for (Map.Entry<String, XmlParseUtil.ParseResult> entry : filteredResults.entrySet()) {
                String fileName = entry.getKey();
                XmlParseUtil.ParseResult parseResult = entry.getValue();

                try {
                    processParseResult(parseResult, result);
                    result.setSuccessFiles(result.getSuccessFiles() + 1);
                    logger.debug("成功处理文件: {}", fileName);
                } catch (Exception e) {
                    result.setFailedFiles(result.getFailedFiles() + 1);
                    result.addErrorMessage("处理文件失败: " + fileName + ", 错误: " + e.getMessage());
                    logger.error("处理文件失败: {}", fileName, e);
                }
            }

            logger.info("按消息类型导入完成 - 消息类型: {}, 总文件数: {}, 成功: {}, 失败: {}",
                    messageType, result.getTotalFiles(), result.getSuccessFiles(), result.getFailedFiles());

        } catch (Exception e) {
            result.addErrorMessage("按消息类型导入过程中发生错误: " + e.getMessage());
            logger.error("按消息类型导入过程中发生错误", e);
        }

        return result;
    }

    /**
     * 单个文件上传导入
     */
    @Transactional(rollbackFor = Exception.class)
    public ImportResult importUploadedFile(MultipartFile file) {
        logger.info("开始导入上传的文件: {}", file.getOriginalFilename());

        ImportResult result = new ImportResult();
        result.setTotalFiles(1);

        try {
            // 创建临时文件
            Path tempFile = Files.createTempFile("upload_", ".xml");
            file.transferTo(tempFile.toFile());

            try {
                // 解析XML文件
                XmlParseUtil.ParseResult parseResult = XmlParseUtil.parseXmlFile(tempFile.toFile());

                // 处理解析结果
                processParseResult(parseResult, result);
                result.setSuccessFiles(1);

                logger.info("成功导入上传文件: {}", file.getOriginalFilename());

            } finally {
                // 清理临时文件
                Files.deleteIfExists(tempFile);
            }

        } catch (Exception e) {
            result.setFailedFiles(1);
            result.addErrorMessage("导入上传文件失败: " + e.getMessage());
            logger.error("导入上传文件失败: {}", file.getOriginalFilename(), e);
        }

        return result;
    }

    /**
     * 处理单个解析结果
     */
    private void processParseResult(XmlParseUtil.ParseResult parseResult, ImportResult result) {
        // 1. 保存消息元数据
        if (parseResult.getMsgMeta() != null) {
            msgMetaMapper.insert(parseResult.getMsgMeta());
            Long metaId = parseResult.getMsgMeta().getId();
            result.setMsgMetaCount(result.getMsgMetaCount() + 1);

            String messageType = parseResult.getMsgMeta().getType() + "-" + parseResult.getMsgMeta().getStyp();
            result.incrementMessageTypeCount(messageType);

            // 2. 保存机场基础信息
            if (parseResult.getAirportInfo() != null) {
                AirportInfo airportInfo = parseResult.getAirportInfo();
                // 检查是否已存在相同机场代码的记录
                QueryWrapper<AirportInfo> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("code", airportInfo.getCode());
                AirportInfo existingAirport = airportInfoMapper.selectOne(queryWrapper);

                if (existingAirport == null) {
                    // 不存在则插入
                    airportInfoMapper.insert(airportInfo);
                    result.setAirportInfoCount(result.getAirportInfoCount() + 1);
                } else {
                    // 存在则更新
                    airportInfo.setId(existingAirport.getId());
                    airportInfoMapper.updateById(airportInfo);
                    result.setAirportInfoCount(result.getAirportInfoCount() + 1);
                }
            }

            // 3. 保存航班动态信息
            if (parseResult.getFlightDynamic() != null) {
                parseResult.getFlightDynamic().setMetaId(metaId);
                flightDynamicMapper.insert(parseResult.getFlightDynamic());
                result.setFlightDynamicCount(result.getFlightDynamicCount() + 1);
            }

            // 4. 保存登机门分配信息
            if (!parseResult.getGateAssignments().isEmpty()) {
                for (GateAssignment assignment : parseResult.getGateAssignments()) {
                    gateAssignmentMapper.insert(assignment);
                    result.setGateAssignmentCount(result.getGateAssignmentCount() + 1);
                }
            }

            // 5. 保存机位分配信息
            if (!parseResult.getStandAssignments().isEmpty()) {
                for (StandAssignment assignment : parseResult.getStandAssignments()) {
                    standAssignmentMapper.insert(assignment);
                    result.setStandAssignmentCount(result.getStandAssignmentCount() + 1);
                }
            }

            // 6. 保存行李转盘分配信息
            if (!parseResult.getBeltAssignments().isEmpty()) {
                for (BeltAssignment assignment : parseResult.getBeltAssignments()) {
                    beltAssignmentMapper.insert(assignment);
                    result.setBeltAssignmentCount(result.getBeltAssignmentCount() + 1);
                }
            }

            // 7. 保存航班基础信息
            if (parseResult.getFlightBase() != null) {
                FlightBase flightBase = parseResult.getFlightBase();
                // 检查是否已存在相同航班号的记录
                QueryWrapper<FlightBase> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("flight_number", flightBase.getFlightNumber());
                queryWrapper.eq("airline_code", flightBase.getAirlineCode());
                queryWrapper.eq("flight_date", flightBase.getFlightDate());
                FlightBase existingFlight = flightBaseMapper.selectOne(queryWrapper);

                if (existingFlight == null) {
                    // 不存在则插入
                    flightBaseMapper.insert(flightBase);
                    result.setFlightBaseCount(result.getFlightBaseCount() + 1);
                } else {
                    // 存在则更新
                    flightBase.setId(existingFlight.getId());
                    flightBaseMapper.updateById(flightBase);
                    result.setFlightBaseCount(result.getFlightBaseCount() + 1);
                }
            }

            // 8. 保存值机显示信息
            if (!parseResult.getCheckinDisplays().isEmpty()) {
                for (CheckinDisplay display : parseResult.getCheckinDisplays()) {
                    checkinDisplayMapper.insert(display);
                    result.setCheckinDisplayCount(result.getCheckinDisplayCount() + 1);
                }
            }
        }
    }

    /**
     * 获取可用的消息类型列表
     */
    public List<String> getAvailableMessageTypes() {
        String xmlFolderPath = "src/main/resources/xml";

        try {
            Map<String, XmlParseUtil.ParseResult> parseResults = XmlParseUtil.parseXmlFolder(xmlFolderPath);
            Map<String, List<XmlParseUtil.ParseResult>> groupedResults = XmlParseUtil.groupResultsByMessageType(parseResults);

            return new ArrayList<>(groupedResults.keySet());
        } catch (Exception e) {
            logger.error("获取消息类型列表失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 清空所有导入的数据
     */
    @Transactional(rollbackFor = Exception.class)
    public void clearAllImportedData() {
        logger.info("开始清空所有导入的数据");

        try {
            // 按照外键依赖顺序删除
            checkinDisplayMapper.delete(null);
            beltAssignmentMapper.delete(null);
            standAssignmentMapper.delete(null);
            gateAssignmentMapper.delete(null);
            flightDynamicMapper.delete(null);
            flightBaseMapper.delete(null);
            airportInfoMapper.delete(null);
            msgMetaMapper.delete(null);

            logger.info("成功清空所有导入的数据");
        } catch (Exception e) {
            logger.error("清空导入数据失败", e);
            throw e;
        }
    }
} 